home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / umich / network / ka9q / ka9q_src.arc / LAPB.C < prev    next >
C/C++ Source or Header  |  1988-07-28  |  11KB  |  447 lines

  1. /* Link Access Procedures Balanced (LAPB) - with changes for rational
  2.  * behavior over packet radio
  3.  */
  4. #include "global.h"
  5. #include "mbuf.h"
  6. #include "timer.h"
  7. #include "ax25.h"
  8. #include "lapb.h"
  9.  
  10. int conok = 1;            /* DG2KK */
  11. extern struct tcb;
  12. #define NULLTCB (struct tcb *)0    /* DG2KK */
  13.  
  14. /* Process incoming frames */
  15. lapb_input(axp,cmdrsp,bp)
  16. struct ax25_cb *axp;        /* Link control structure */
  17. char cmdrsp;            /* Command/response flag */
  18. struct mbuf *bp;        /* Rest of frame, starting with ctl */
  19. {
  20.     int16 ftype();
  21.     char control;
  22.     char frej = 0;        /* FRMR reject reason code */
  23.     char class;        /* General class (I/S/U) of frame */
  24.     int16 type;        /* Specific type (I/RR/RNR/etc) of frame */
  25.     char pf;        /* extracted poll/final bit */
  26.     char polled = 0;
  27.     char remote[10];    /* DG2KK */
  28.  
  29.     if(bp == NULLBUF || axp == NULLAX25){
  30.         free_p(bp);
  31.         return;
  32.     }
  33.     control = pullchar(&bp);
  34.     type = ftype(control);
  35.     class = type & 0x3;
  36.     pf = control & PF;
  37.  
  38.     /* Check for polls */
  39.     if(cmdrsp == COMMAND && pf)
  40.         polled = YES;
  41.  
  42.     /* While we're disconnected, ignore all except SABM and DISC */
  43.     if(axp->state == DISCONNECTED && type != SABM && type != DISC){
  44.         if(polled)
  45.             axp->response = DM;
  46.         goto done;
  47.     }
  48.     /* Process implicit acknowledgements in all but U-frames */
  49.     if(class != U && ackours(axp,(control >> 5) & MMASK) == -1)
  50.         frej = Z;    /* Out of range sequence number */
  51.  
  52.     if(type != I && type != FRMR && len_mbuf(bp) != 0)
  53.         frej |= X|W;    /* I-field not allowed */
  54.  
  55.     /* Process final bit if a poll was outstanding */
  56.     if(axp->waitack && class != U && pf && cmdrsp == RESPONSE){
  57.         axp->waitack = NO;
  58.         axp->retries = 0;
  59.         stop_timer(&axp->t1);
  60.         /* Pick up retransmission at proper point */
  61.         axp->vs -= axp->unack;
  62.         axp->vs &= MMASK;
  63.         axp->unack = 0;
  64.     }
  65.     /* Resend FRMR for all except certain U while in error state */
  66.     if(axp->state == FRAMEREJECT && class != U){
  67.         goto done;
  68.     }
  69.     switch(type){
  70.     case SABM:    /* Initialize or reset link */
  71.         /* we arrive here when we receive a SABM directed to us. */
  72.         /* put remote callsign in 'remote' */
  73.         pax25(remote, &axp->addr.dest);        /* DG2KK */
  74.         log(NULLTCB,"Connect request from %s (%d)", remote, conok);
  75. if (conok != 0 || axp->state != DISCONNECTED) {        /* DG2KK */
  76.         switch(axp->state){
  77.         case DISCONNECTED:
  78.         case FRAMEREJECT:
  79.         case CONNECTED:        /* note fall-through */
  80.             lapbstate(axp,CONNECTED);/* Resets state counters */
  81.             axp->response = UA;
  82.             break;
  83.         case DISCPENDING:
  84.             axp->response = DM;
  85.             break;
  86.         case SETUP:
  87.             axp->response = UA;
  88.             break;
  89.         }
  90. } else {
  91.         polled = NO;        /* DG2KK */
  92. }
  93.         break;
  94.     case UA:
  95.         axp->retries = 0;
  96.         switch(axp->state){
  97.         case CONNECTED:
  98.             lapbstate(axp,SETUP);
  99.             sendctl(axp,COMMAND,SABM|PF);
  100.             break;
  101.         case SETUP:
  102.             stop_timer(&axp->t1);
  103.             lapbstate(axp,CONNECTED);
  104.             break;
  105.         case DISCPENDING:
  106.             lapbstate(axp,DISCONNECTED);
  107.             break;
  108.         /* note - ignored if DISCONNECTED or in FRAMEREJECT state */
  109.         }
  110.         break;
  111.     case DISC:
  112.         switch(axp->state){
  113.         case SETUP:
  114.             lapbstate(axp,DISCONNECTED);
  115.             axp->response = DM;
  116.             break;
  117.         case DISCPENDING:
  118.             axp->response = UA;
  119.             break;
  120.         default:
  121.             axp->response = UA;
  122.             lapbstate(axp,DISCONNECTED);
  123.             break;
  124.         }
  125.         break;
  126.     case RR:
  127.         axp->remotebusy = NO;
  128.         break;
  129.     case RNR:
  130.         axp->remotebusy = YES;
  131.         axp->retries = 0;
  132.         start_timer(&axp->t1);    /* Probe as long as necessary */
  133.         break;
  134.     case REJ:
  135.         /* Crank back V(s) to start of queue */
  136.         axp->vs -= axp->unack;
  137.         axp->vs &= MMASK;
  138.         axp->unack = 0;
  139.         break;
  140.     case I:
  141.         if(len_mbuf(axp->rxq) >= axp->window){
  142.             /* Too bad he didn't listen to us; he'll
  143.              * have to resend the frame later. This
  144.              * drastic action is necessary to avoid
  145.              * deadlock.
  146.              */
  147.             axp->response = RNR;
  148.             free_p(bp);
  149.             bp = NULLBUF;
  150.             break;
  151.         }
  152.         /* Reject or ignore I-frames with receive sequence number errors */
  153.         if(((control>>1) & MMASK) != axp->vr){
  154.             if(axp->proto == V1 || !axp->rejsent){
  155.                 axp->rejsent = YES;
  156.                 axp->response = REJ;
  157.             }
  158.             break;
  159.         }
  160.         axp->rejsent = NO;
  161.         axp->vr = (axp->vr+1) & MMASK;
  162.         axp->response = len_mbuf(axp->rxq) >= axp->window ? RNR : RR;
  163.         procdata(axp,bp);
  164.         bp = NULLBUF;
  165.         break;
  166.     case FRMR:
  167.         if(axp->state == FRAMEREJECT || axp->state == CONNECTED){
  168.             lapbstate(axp,SETUP);
  169.             sendctl(axp,COMMAND,SABM|PF);
  170.         }
  171.         break;
  172.     case DM:
  173.         switch(axp->state){
  174.         case SETUP:
  175.         case DISCPENDING:
  176.             lapbstate(axp,DISCONNECTED);
  177.             break;
  178.         default:
  179.             lapbstate(axp,SETUP);
  180.             sendctl(axp,COMMAND,SABM|PF);
  181.         }
  182.         break;
  183.     default:
  184.         frej |= W;
  185.         break;
  186.     }
  187. done:
  188.     free_p(bp);    /* In case anything's left */
  189.  
  190.     /* Check if we have to make some sort of response to this frame */
  191.     if(frej){
  192.         /* Frame reject state, respond only with FRMR */
  193.         frmr(axp,control,frej);
  194.         return;
  195.     }
  196.     /* If we're being polled or have a U-frame response, respond
  197.      * immediately
  198.      */
  199.     if(polled || (axp->response & 0x3) == U){
  200.         if(axp->response == 0)
  201.             axp->response = len_mbuf(axp->rxq) >= axp->window ? RNR : RR;
  202.         sendctl(axp,RESPONSE,axp->response|PF);
  203.         stop_timer(&axp->t2);    /* No need for delayed response */
  204.         axp->response = 0;
  205.     }
  206.     /* See if we can send some data, perhaps piggybacking an ack.
  207.      * If successful, lapb_output will clear axp->response.
  208.      */
  209.     lapb_output(axp);
  210.  
  211.     if(axp->response){
  212.         /* We STILL owe him an ack. Try to delay it, but if T2 is
  213.          * disabled, send it right away
  214.          */
  215.         if(axp->t2.start != 0){
  216.             start_timer(&axp->t2);
  217.         } else {
  218.             sendctl(axp,RESPONSE,axp->response);
  219.             axp->response = 0;
  220.         }
  221.     }
  222.     /* Restart timer T1 if there are still unacknowledged I-frames or
  223.      * a poll outstanding.
  224.      */
  225.     if(axp->state != DISCONNECTED && (axp->unack !=0 || axp->waitack))
  226.         start_timer(&axp->t1);
  227.     /* Start timer T3 (the idle poll timer) under AX.25 V2.0
  228.      * whenever T1 is stopped, unless we are disconnected
  229.      */
  230.     if(axp->state != DISCONNECTED && axp->t1.state != TIMER_RUN
  231.      && axp->t3.start != 0 && axp->proto == V2)
  232.         start_timer(&axp->t3);
  233.     else
  234.         stop_timer(&axp->t3);
  235.  
  236.     /* Empty the trash */
  237.     if(axp->state == DISCONNECTED)
  238.         del_ax25(axp);
  239. }
  240. /* Handle incoming acknowledgements for frames we've sent.
  241.  * Free frames being acknowledged.
  242.  * Return -1 to cause a frame reject if number is bad, 0 otherwise
  243.  */
  244. static
  245. ackours(axp,n)
  246. struct ax25_cb *axp;
  247. char n;
  248. {    
  249.     struct mbuf *bp;
  250.     int acked = 0;    /* Count of frames acked by this ACK */
  251.     int oldest;    /* Seq number of oldest unacked I-frame */
  252.  
  253.     /* Free up acknowledged frames by purging frames from the I-frame
  254.      * transmit queue. Start at the remote end's last reported V(r)
  255.      * and keep going until we reach the new sequence number.
  256.      * If we try to free a null pointer,
  257.      * then we have a frame reject condition.
  258.      * Stop the T1 timer if at least one frame is being acknowledged;
  259.      * it will be restarted again if not all frames were acknowledged.
  260.      */
  261.     oldest = (axp->vs - axp->unack) & MMASK;
  262.     while(axp->unack != 0 && oldest != n){
  263.         if((bp = dequeue(&axp->txq)) == NULLBUF){
  264.             /* Acking unsent frame */
  265.             return -1;
  266.         }
  267.         free_p(bp);
  268.         axp->unack--;
  269.         acked++;
  270.         stop_timer(&axp->t1);
  271.         axp->retries = 0;
  272.         oldest = (oldest + 1) & MMASK;
  273.     }
  274.     /* If user has set a transmit upcall, indicate how many frames
  275.      * may be queued
  276.      */
  277.     if(acked != 0 && axp->t_upcall != NULLVFP)
  278.         (*axp->t_upcall)(axp,axp->paclen * (axp->maxframe - axp->unack));
  279.  
  280.     return 0;
  281. }
  282.  
  283. /* Generate Frame Reject (FRMR) response
  284.  * If reason != 0, this is the initial error frame
  285.  * If reason == 0, resend the last error frame
  286.  */
  287. frmr(axp,control,reason)
  288. register struct ax25_cb *axp;
  289. char control;
  290. char reason;
  291. {
  292.     struct mbuf *frmrinfo;
  293.     register char *cp;
  294.  
  295.     if(reason != 0){
  296.         cp = axp->frmrinfo;
  297.         *cp++ = control;
  298.         *cp++ =  axp->vr << 5 || axp->vs << 1;
  299.         *cp = reason;
  300.     }
  301.     lapbstate(axp,FRAMEREJECT);
  302.     if((frmrinfo = alloc_mbuf(3)) == NULLBUF)
  303.         return;    /* No memory */
  304.     frmrinfo->cnt = 3;
  305.     memcpy(frmrinfo->data,axp->frmrinfo,3);
  306.     sendframe(axp,RESPONSE,FRMR|(control&PF),frmrinfo);
  307. }
  308.  
  309. /* Send S or U frame to currently connected station */
  310. sendctl(axp,cmdrsp,cmd)
  311. struct ax25_cb *axp;
  312. char cmdrsp,cmd;
  313. {
  314.     int16 ftype();
  315.  
  316.     if((ftype(cmd) & 0x3) == S)    /* Insert V(R) if S frame */
  317.         cmd |= (axp->vr << 5);
  318.     sendframe(axp,cmdrsp,cmd,NULLBUF);
  319. }
  320. /* Start data transmission on link, if possible
  321.  * Return number of frames sent
  322.  */
  323. int
  324. l